package com.yk.common.core.utils;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yk.common.core.constant.Constants;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * Http请求工具类
 *
 * @author lmx
 * @date 2023/11/8 9:40
 */
@Slf4j
public class HttpUtils {

    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
    private static final String CONTENT_TYPE_NAME = "Content-Type";
    private static final String JSON_CONTENT_TYPE = "application/json";

    private static final String GET = "GET";
    private static final String POST = "POST";

    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param) {
        return sendGet(url, param, Constants.UTF8);
    }


    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url         发送请求的 URL
     * @param param       请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @param contentType 编码类型
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param, String contentType) {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try {
            String urlNameString = url + "?" + param;
            log.info("sendGet - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            URLConnection connection = realUrl.openConnection();
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            connection.connect();
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            log.info("recv - {}", result);
        } catch (ConnectException e) {
            log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception ex) {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }

    private static CloseableHttpClient createClient() {
        return HttpClientBuilder.create().build();
    }

    private static CloseableHttpClient createClient(String username, String password) {
        HttpClientBuilder builder = HttpClientBuilder.create();
        CredentialsProvider provider = new BasicCredentialsProvider();
        AuthScope scope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM);
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
        provider.setCredentials(scope, credentials);
        builder.setDefaultCredentialsProvider(provider);
        return builder.build();
    }

    private static HttpGet setGetParams(String url, Map<String, String> params) throws URISyntaxException {
        URIBuilder uriBuilder = new URIBuilder(url);
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                uriBuilder.setParameter(entry.getKey(), entry.getValue());
            }
        }
        return new HttpGet(uriBuilder.build());
    }

    private static HttpPost setPostParams(String url, Map<String, String> params) {
        HttpPost post = new HttpPost(url);
        if (params != null) {
            StringEntity entity = new StringEntity(JSONUtil.toJsonStr(params), DEFAULT_CHARSET);
            entity.setContentType(JSON_CONTENT_TYPE);
            post.setEntity(entity);
        }
        return post;
    }

    private static void setHeader(HttpRequestBase requestBase, Map<String, String> headers) {
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                requestBase.setHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    private static String getResult(HttpResponse response) throws IOException, HttpException {
        String charset_1 = getCharset(response);
        Charset charset;
        if (charset_1 == null) {
            charset = DEFAULT_CHARSET;
        } else {
            charset = Charset.forName(charset_1.split(",")[0]);
        }

        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            return EntityUtils.toString(response.getEntity(), charset);
        } else {
            int code = response.getStatusLine().getStatusCode();
            String message = response.getEntity().toString();
            throw new HttpException(code + " " + message);
        }
    }

    private static String getCharset(HttpResponse response) {
        Header contentType = response.getFirstHeader(CONTENT_TYPE_NAME);

        String regex = "charset=(.*)";

        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(contentType.getValue());
        if (m.find()) {
            return m.group(1);
        } else {
            return null;
        }
        /*for (Header header : response.getAllHeaders()) {
            StringBuffer buffer = new StringBuffer(header.getName());
            buffer.append(": [").append(header.getValue()).append("]");
            System.out.println(buffer);
        }*/
    }


    public static String doPost(String host, String param, String auth, Charset charset) throws MalformedURLException {
        URL url = new URL(host);
        HttpURLConnection conn;
        try {
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setConnectTimeout(30 * 1000);
            conn.setReadTimeout(10 * 1000);
            conn.setDoInput(true);
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Authorization", "Basic " + auth);
            try (OutputStream out = conn.getOutputStream();
                 OutputStreamWriter writer = new OutputStreamWriter(out, charset)) {
                writer.write(param);
                writer.flush();
                return getResponse(conn, charset);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            System.out.println("END");
        }
    }


    private static String getResponse(HttpURLConnection conn, Charset charset) throws IOException {
        if (conn.getResponseCode() == 200) {
            StringBuilder result = new StringBuilder();
            try (InputStream in = conn.getInputStream();
                 BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }
            }
            return result.toString();
        } else {
            try {
                InputStream in = conn.getErrorStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset));
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
            return null;
        }
    }

    /**
     * https post 请求
     *
     * @param urlPath 请求地址
     * @param json    请求参数
     * @return response
     */
    public static String doPostToJson(String urlPath, String json) {

        String result = "";
        BufferedReader reader = null;
        HttpURLConnection conn;
        try {
            trustAllHosts();
            URL url = new URL(urlPath);
            if ("https".equals(url.getProtocol().toLowerCase())) {
                HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
                httpsConn.setHostnameVerifier(DO_NOT_VERIFY);
                conn = httpsConn;
            } else {
                conn = (HttpURLConnection) url.openConnection();
            }

            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Charset", "UTF-8");
            conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            conn.setRequestProperty("accept", "application/json");
            if (json != null) {
                byte[] writebytes = json.getBytes();
                conn.setRequestProperty("Content-Length", String.valueOf(writebytes.length));
                OutputStream outputStream = conn.getOutputStream();
                outputStream.write(json.getBytes());
                outputStream.flush();
                outputStream.close();
            }

            if (conn.getResponseCode() == 200) {
                reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
                result = reader.readLine();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * 向指定URL发送POST方法的请求 Content-Type=application/x-www-form-urlencoded
     *
     * @param targetUrl 发送请求的URL
     * @param params    请求参数，请求参数应该是name1=value1&name2=value2的形式。
     * @return JSONObject 返回的JSON数据
     */
    public static JSONObject postFormUrlEncoded(String targetUrl, String params) {
        HttpURLConnection urlConnection = null;
        try {
            URL url = new URL(targetUrl.trim());
            urlConnection = (HttpURLConnection) url.openConnection();
            // 设置请求方式
            urlConnection.setRequestMethod("POST");
            // 设置数据类型
            urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            // 设置允许输入输出
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            // 设置不用缓存
            urlConnection.setUseCaches(false);

            urlConnection.connect();
            PrintWriter out = new PrintWriter(new OutputStreamWriter(urlConnection.getOutputStream(), StandardCharsets.UTF_8));
            // 写入传递参数,格式为a=b&c=d
            out.print(params);
            out.flush();

            int resultCode = urlConnection.getResponseCode();
            if (HttpURLConnection.HTTP_OK == resultCode) {
                StringBuffer stringBuffer = new StringBuffer();
                String readLine;
                BufferedReader responseReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), StandardCharsets.UTF_8));
                while ((readLine = responseReader.readLine()) != null) {
                    stringBuffer.append(readLine);
                }
                responseReader.close();
                return new JSONObject(stringBuffer.toString());
            }
            out.close();
        } catch (Exception e) {
            return null;
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
        }
        return null;
    }


    final static HostnameVerifier DO_NOT_VERIFY = (arg0, arg1) -> true;

    public static void trustAllHosts() {
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[]{};
            }

            @Override
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) {

            }

            @Override
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) {

            }
        }

        };
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
